﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace NPortableEngine
{
    public class NTaskScheduler
    {
        #region Singleton

        private static NTaskScheduler _instance;

        public NTaskScheduler()
        {
           
        }

        public static NTaskScheduler Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new NTaskScheduler();
                }
                return _instance;
            }
        }

        #endregion

        #region Fields
        
        //线程数
        [ThreadStatic]
        private static bool _currentThreadIsProcessingItems;//判断当前线程是否在工作中
        private readonly LinkedList<NTaskContainer> _allTasks = new LinkedList<NTaskContainer>();//所有的任务,来的所有任务都放入
        private readonly int _maxDegreeOfParalleism = 1;//并发的线程数
        private int _delegateQueueOrRunning = 0;//protected by lock(_tasks)

        #endregion

        #region Properties

        public int MaximumConcurrencyThreadNum
        {
            get
            {
                return _maxDegreeOfParalleism;
            }
        }

        #endregion

        #region Method

        public void QueueTask(INDeliver deliver,INDeliverExecutor executor)
        {
            lock (_allTasks)
            {
                NTaskContainer container = new NTaskContainer(deliver,executor);
                _allTasks.AddLast(container);
                
                if (_delegateQueueOrRunning < _maxDegreeOfParalleism)
                {
                    ++_delegateQueueOrRunning;
                    NotifyThreadPoolOfPendingWork();
                }
            }
        }

        private void NotifyThreadPoolOfPendingWork()
        {
            Task.Run(() =>
                {
                    _currentThreadIsProcessingItems = true;
                    try
                    {
                        while (true)
                        {
                            NTaskContainer executeContainer = null;
                            NTaskContainer removeContainer = null;
                            lock (_allTasks)
                            {
                                if (_allTasks.Count == 0)
                                {
                                    --_delegateQueueOrRunning;
                                    break;
                                }
                                if (_allTasks.Count < 40)
                                {
                                    executeContainer = _allTasks.Where(x => !(x.Executor.CheckIsRunning())).FirstOrDefault();
                                }
                                else
                                {
                                    Debug.WriteLine("-------==大于最大容量==--------");
                                    removeContainer = _allTasks.First.Value;
                                }
                            }
                            if (removeContainer != null)
                            {
                                if (removeContainer.Executor.CheckIsRunning())
                                {
                                    removeContainer.Executor.Cancel();
                                }
                                lock (_allTasks)
                                {
                                    _allTasks.Remove(removeContainer);
                                }
                            }
                            if (executeContainer != null)
                            {
                                executeContainer.Executor.CompleteAciton = () =>
                                {
                                    lock (_allTasks)
                                    {
                                        _allTasks.Remove(executeContainer);
                                    }
                                };
                                executeContainer.Executor.Execute(executeContainer.Deliver);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("Thread TaskScheduler has errors :" + ex.Message.ToString());
                    }
                    _currentThreadIsProcessingItems = false;
                });
        }

        #region TODeal

        internal IEnumerable<NTaskContainer> GetScheduledTasks()
        {
            bool lockTaken = false;
            try
            {
                Monitor.TryEnter(_allTasks, ref lockTaken);
                if (lockTaken)
                {
                    return _allTasks;
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
            finally
            {
                if (lockTaken)
                {
                    Monitor.Exit(_allTasks);
                }
            }
        }

        internal void TryExecuteTaskInline(NTaskContainer container, bool taskWasPreviouslyQueued)
        {
            if (!_currentThreadIsProcessingItems)
            {
                return;
            }
            if (taskWasPreviouslyQueued)
            {
                TryDequeue(container);
            }
            //task.Start();
        }

        internal bool TryDequeue(NTaskContainer container)
        {
            //lock (_tasks)
            //{
            //    return _tasks.Dequeue(container);
            //}
            return false;
        }

        #endregion
        
        #endregion
    }
}
